﻿package com.everydayflash.away3d.earth {
	
	import away3d.containers.View3D;
	import away3d.primitives.RegularPolygon;
	import away3d.primitives.Skybox;
	import flash.display.Bitmap;
	import flash.filters.GlowFilter;
	
	import away3d.primitives.Sphere;
	import away3d.primitives.Cube;
	
	import away3d.lights.PointLight3D;
	
	import away3d.materials.ColorMaterial;
	import away3d.materials.BitmapMaterial;
	import away3d.materials.WhiteShadingBitmapMaterial;
	
	import away3d.core.math.Number3D;
	import away3d.core.base.Object3D;
	import away3d.core.base.Mesh;
	
	import flash.display.Sprite;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.KeyboardEvent;
	import flash.ui.Keyboard;
	import flash.display.BitmapData;
	
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.display.StageQuality;
	
	public class EarthDemo extends Sprite {
		
		private var view:View3D;
		
		private var starField:Skybox;
		private var earth:Sphere;
		private var sun:Mesh;
		private var moon:Sphere;
		private var sunLight:PointLight3D;
		
		private var instruction:Instruction;
		
		private var earthRotation:Number = Math.PI;
		private var moonDistance:Number = 400;
		private var moonEllipse:Number = 5;
		
		private var CAM_Y_BASE:Number;
		private var CAM_X_BASE:Number;
		private var mouseMultiplier:Number = -50;
		private var mouseEasing:Number = .2;
		private var simulationRate:Number = 1;
		
		private var cameraLocations:Array;
		private var cameraLocIndex:int = -1;
		
		private var paused:Boolean = false;
		private var simRateAcc:Number = 0;

		[Embed(source = "../../../../../../as3/away/assets/earth-map-640x320-small.jpg")]
		private var Earth:Class;
		
		[Embed(source = "../../../../../../as3/away/assets/moon-125x63.jpg")]
		private var Moon:Class;
		
		[Embed(source = "../../../../../../as3/away/assets/stars.png")]
		private var Stars:Class;

		/**
		 * Document class for the away3d demo presented here:
		 * http://www.everydayflash.com/blog/index.php/2008/04/26/light-shading-away3d/
		 * 
		 * Check the downloads section for a ZIP containg this class and the assest used (see above)
		 * http://code.google.com/p/barteksplayground/downloads/list
		 * 
		 * @author Bartek Drozdz [www.everydayflash.com]
		 * 
		 * NOTE: Compiled with Away3D rev. 494, lighting doesn't work with newer versions.
		 */
		public function EarthDemo() { 
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.quality = StageQuality.LOW;
			
			init();
			
			instruction = new Instruction();
			addChild(instruction);
			
			cameraLocations = new Array();
			cameraLocations.push({ loc:new Number3D(-400, 0, 1500), lookAt:new Number3D(400, 0, 0), attachTo:null, name:"side" });
			cameraLocations.push({ loc:new Number3D(1800, 0, -1000), lookAt:new Number3D(0, 0, 0), attachTo:null, name:"sun perspective" });
			cameraLocations.push( { loc:new Number3D(160, 0, 0), lookAt:new Number3D(0, 0, 0), attachTo:earth, name:"earth perspective" } );
			cameraLocations.push( { loc:new Number3D(0, 0, 0), lookAt:new Number3D(0, 0, 0), attachTo:moon, name:"moon perspective" } );
			cameraLocations.push( { loc:new Number3D(-1800, 0, 1500), lookAt:new Number3D(0, 0, 0), attachTo:null, name:"behind" } );
			cameraLocations.push( { loc:new Number3D(1200, 5000, -600), lookAt:new Number3D(1200, 0, -600), attachTo:null, name:"top" } );
			
			changeCameraLocation();
			
			addEventListener(Event.ENTER_FRAME, render);
			addEventListener(MouseEvent.MOUSE_WHEEL, zoom);
			addEventListener(MouseEvent.MOUSE_UP, changeCameraLocation);
			stage.addEventListener(Event.RESIZE, updateView);
			
			stage.addEventListener(KeyboardEvent.KEY_DOWN, handleKeyDown);
			stage.addEventListener(KeyboardEvent.KEY_UP, handleKeyUp);
		}
		

		
		private function init():void {
			// View
			view = new View3D();
			view.x = stage.stageWidth / 2;
			view.y = stage.stageHeight / 2;
			addChild(view);
			
			// Light
			sunLight = new PointLight3D( { x:1200, y:0, z: -600, brightness:5, ambient:30, diffuse:500, specular:180 } );
			view.scene.addChild(sunLight);
			
			// Sun
			var sunMat:ColorMaterial = new ColorMaterial(0xffffff);
			sun = new RegularPolygon( { material:sunMat, radius:100, sides:32, x:2400, y:0, z: -1200 } );
			sun.rotationZ = 90;
			view.scene.addChild(sun);
			sun.ownCanvas = true;
			sun.filters = [new GlowFilter(0xffffbe, 1, 12, 12, 3, 3, false, false), new GlowFilter(0xffffbe, 1, 12, 12, 3, 3, true, false)];
			
			// Earth
			var earthBmp:Bitmap = new Earth() as Bitmap;
			var earthMat:WhiteShadingBitmapMaterial = new WhiteShadingBitmapMaterial(earthBmp.bitmapData);
			earthMat.ambient_brightness = 2;
			earthMat.diffuse_brightness = 1.7;
			earthMat.specular_brightness = 0;
			earth = new Sphere( { material:earthMat, radius:150, segmentsW:32, segmentsH:18, y:0, x:0, z:0 } );
			earth.rotationZ = -8;
			view.scene.addChild(earth);
			
			// Moon
			var moonBmp:Bitmap = new Moon() as Bitmap;
			var moonMat:WhiteShadingBitmapMaterial = new WhiteShadingBitmapMaterial(moonBmp.bitmapData);
			moonMat.ambient_brightness = 0;
			moonMat.diffuse_brightness = 1.2;
			moonMat.specular_brightness = 0;
			moon = new Sphere( { material:moonMat, radius:16, segmentsW:24, segmentsH:12, y:0, x:moonDistance, z:moonDistance } );
			view.scene.addChild(moon);
			
			
			
			var starBmp:Bitmap = new Stars() as Bitmap;
			var starFieldMat:BitmapMaterial = new BitmapMaterial(starBmp.bitmapData);
			starField = new Skybox(starFieldMat, starFieldMat, starFieldMat, starFieldMat, starFieldMat, starFieldMat);
			view.scene.addChild(starField);
			
			sunLight.lookAt(new Number3D(0, 0, 0));
			
			
		}
		
		private function handleKeyDown(ke:KeyboardEvent):void {
			switch (ke.keyCode) {
				case 32:
					paused = true;
					break;
				case Keyboard.LEFT:
				case Keyboard.DOWN:
					simRateAcc = -.1;
					break;
				case Keyboard.RIGHT:
				case Keyboard.UP:
					simRateAcc = .1; 
					break;
			}
		}
		
		private function handleKeyUp(ke:KeyboardEvent):void {
			paused = false;
			simRateAcc = 0;
		}
		
		private function zoom(me:MouseEvent):void {
			if (view.camera.zoom < 4 && me.delta < 1) return;
			if (view.camera.zoom > 50 && me.delta > 1) return;
			
			var nz:Number = me.delta / 10;
			view.camera.zoom += nz;
		}
		
		private function changeCameraLocation(e:Event = null):void {
			if (cameraLocIndex > -1 && cameraLocations[cameraLocIndex].attachTo != null)
				cameraLocations[cameraLocIndex].attachTo.visible = true;
			
			cameraLocIndex++;
			if (cameraLocIndex == cameraLocations.length) cameraLocIndex = 0;
			
			view.camera.position = cameraLocations[cameraLocIndex].loc;
			if (cameraLocations[cameraLocIndex].lookAt != null) view.camera.lookAt(cameraLocations[cameraLocIndex].lookAt);
			
			CAM_Y_BASE = view.camera.rotationY;
			CAM_X_BASE = view.camera.rotationX;
			
			view.camera.zoom = 10;
			
			if (cameraLocations[cameraLocIndex].name == "top") {
				sun.rotationZ = 0;
			} else {
				sun.rotationZ = 90;
			}
			
			instruction.setViewName(cameraLocations[cameraLocIndex].name);
		}
		
		private function updateView(e:Event):void {
			view.x = stage.stageWidth / 2;
			view.y = stage.stageHeight / 2;
		}
		
		private function render(event:Event):void {
			if (paused) return;
			
			if(simRateAcc != 0) {
				simulationRate += simRateAcc;
				if (simulationRate < .5) simulationRate = .5;
				if (simulationRate > 20) simulationRate = 20;
			}
			
			earth.rotationY -= simulationRate;
			moon.rotationY += simulationRate * 0.1;

			moon.x = Math.cos(earthRotation) * moonDistance;
			moon.z = Math.sin(earthRotation) * moonDistance;
			moon.y = Math.sin(earthRotation) * moonEllipse;
			earthRotation -= (simulationRate * 0.1) / 180 * Math.PI;
			
			
			if(cameraLocations[cameraLocIndex].attachTo == null) {
				var mx:Number = CAM_Y_BASE + (mouseX - stage.stageWidth / 2) / mouseMultiplier;
				var my:Number = CAM_X_BASE + (mouseY - stage.stageHeight / 2) / mouseMultiplier;
				
				var vx:Number = mx - view.camera.rotationY;
				var vy:Number = my - view.camera.rotationX;
				
				view.camera.rotationY += vx * mouseEasing;
				view.camera.rotationX += vy * mouseEasing;
				
				var fgw:Number = view.camera.rotationY;
				var fgh:Number = view.camera.rotationX;
			} else {
				var att:Mesh = cameraLocations[cameraLocIndex].attachTo as Mesh;
				att.visible = false;
				view.camera.position = att.position;
				if (att == moon) view.camera.lookAt(cameraLocations[cameraLocIndex].lookAt);
				else if (att == earth) view.camera.rotationY = earth.rotationY * -1;
			}
			
			if (cameraLocations[cameraLocIndex].name == "top") {
				sun.rotationX = 0;
			} else {
				var sx:Number = sun.x - view.camera.x;
				var sz:Number = sun.z - view.camera.z;
				var sa:Number = Math.atan2(sz, sx);
				sun.rotationX = sa  * 180 / Math.PI;
			}
			
			view.render();
		}
	}
}












